package de.dailab.prefgen;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import de.dailab.prefgen.INameMapping.TYPE;


import android.content.Context;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;

public class PreferenceFactory {

	private final PreferenceActivity context;
	private final INameMapping nameMapping;
	private List<ILeafFactory> leafs = new LinkedList<ILeafFactory>();
	private PreferenceFactoryWrapper wrapper;

	public PreferenceFactory(PreferenceActivity context,
			INameMapping nameMapping) {
		this.context = context;
		this.nameMapping = nameMapping;

	}

	public void addLeaf(ILeafFactory leaf) {
		leafs.add(leaf);
	}

	public PreferenceScreen generate(Object object,
			PreferenceScreen createPreferenceScreen) {

		wrapper = new PreferenceFactoryWrapper(context, nameMapping, leafs);
		return wrapper.generate(object, createPreferenceScreen);
	}

}

class PreferenceFactoryWrapper {

	private final PreferenceActivity context;
	private List<ILeafFactory> leafs = new LinkedList<ILeafFactory>();
	private Map<Class, ILeafFactory> leafMapping = new HashMap<Class, ILeafFactory>();
	private INameMapping nameMapping;

	public PreferenceFactoryWrapper(PreferenceActivity context,
			INameMapping nameMapping, List<ILeafFactory> leafs) {
		this.context = context;
		this.nameMapping = nameMapping;
		this.leafs = leafs;
	}

	public PreferenceScreen generate(Object superObject, PreferenceScreen root) {

		if (superObject != null) {

			Method[] methods = superObject.getClass().getMethods();

			for (Method m : methods) {
				if (m.getName().matches("get[A-Z][a-zA-Z\\_0-9]*")
						&& m.getParameterTypes().length == 0
						&& m.getDeclaringClass().equals(superObject.getClass())) {
					// is a getter by Convention

					Class type = m.getReturnType();

					if (Utils.isElement(type)) {
						// Flat rendering

						ILeafFactory leaf = leafMapping.get(type);

						// Add a new Leaf to quick leaf mapper
						if (leaf == null) {
							for (ILeafFactory l : leafs) {
								if (l.shouldGenerate(type)) {
									leaf = l;
									break;
								}
							}
						}

						if (leaf != null) {
							Preference generate = leaf.generate(superObject, m,
									context, nameMapping);
							root.addPreference(generate);

						} else {
							System.err.println("No mapping found for type "
									+ type);
						}

					} else if (Utils.isCollection(type)) {
						// That is also a kind of Leaf but it should be rendered
						// Element by Element recursively

						/**
						 * TODO Add "add new element" as menu to the List
						 */

						Collection col;
						try {

							col = (Collection) m.invoke(superObject, null);

							PreferenceScreen submenue = context
									.getPreferenceManager()
									.createPreferenceScreen(context);
							submenue.setKey(nameMapping.toHumanReadable(m,
									superObject, TYPE.KEY));
							submenue.setTitle(nameMapping.toHumanReadable(m,
									superObject, TYPE.NAME));
							submenue.setSummary(nameMapping.toHumanReadable(m,
									superObject, TYPE.DESCRIPTION));

							int count = 0;
							for (Object o : col) {

								PreferenceScreen subsubmenue = context
										.getPreferenceManager()
										.createPreferenceScreen(context);
								subsubmenue.setKey(nameMapping.toHumanReadable(
										m, o, TYPE.KEY)
										+ count);
								subsubmenue.setTitle(nameMapping
										.toHumanReadable(m, o,
												TYPE.NAME_BY_ANNOTATION));
								subsubmenue
										.setSummary(nameMapping
												.toHumanReadable(m, o,
														TYPE.DESCRIPTION));

								PreferenceScreen generate = generate(o,
										subsubmenue);
								submenue.addPreference(subsubmenue);
								count++;
							}

							root.addPreference(submenue);

						} catch (IllegalArgumentException e) {
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						} catch (InvocationTargetException e) {
							e.printStackTrace();
						}

					} else {
						// submenu rendering

						PreferenceScreen submenue = context
								.getPreferenceManager().createPreferenceScreen(
										context);
						submenue.setKey(nameMapping.toHumanReadable(m,
								superObject, TYPE.KEY));
						submenue.setTitle(nameMapping.toHumanReadable(m,
								superObject, TYPE.NAME));
						submenue.setSummary(nameMapping.toHumanReadable(m,
								superObject, TYPE.DESCRIPTION));
						// Anotation
						// submenue.setSummary("Controll the interface change behavior.");
						try {
							Object obj = m.invoke(superObject, null);
							if (obj != null) {
								submenue = generate(obj, submenue);
								root.addPreference(submenue);
							} else {
								System.err.println("Null Value Object in "
										+ m.getName());
							}

						} catch (IllegalArgumentException e) {
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						} catch (InvocationTargetException e) {
							e.printStackTrace();
						}

					}

				} 
			}

			return root;

		}

		return null;
	}
}
